Read in files
and convert to wide format
#4CE long format Labs Data
patient_obs <- read_csv('penn-data/labs_long_thrombo_v2.csv') %>%
mutate(severity = (severe_ind == 1) %>%
as_factor() %>%
fct_recode('nonsevere' = 'FALSE', 'severe' = 'TRUE'))
#Code, Descriptions and Ranges
lab_mapping <- read_csv('public-data/loinc-map.csv')
load('public-data/lab.range.rda')
# load('public-data/code.dict.rda')
lab_bounds <- lab.range[, -1] %>%
colMeans() %>%
data.frame(value = .) %>%
rownames_to_column() %>%
separate(col = rowname, into = c('LOINC', 'bound'), sep = '_') %>%
mutate(LOINC = gsub('loinc', '', LOINC) %>% gsub('\\.', '-', .),
value = exp(value)) %>%
pivot_wider(names_from = 'bound', values_from = 'value') %>%
left_join(lab_mapping, by = 'LOINC') %>%
{.}
patient_obs_wide <- patient_obs %>%
left_join(lab_bounds, by = c('concept_code' = 'LOINC')) %>%
select(- concept_code) %>%
pivot_wider(id_cols = c(patient_num, days_since_admission, severity),
names_from = short_name,
values_from = value,
values_fn = mean)
#check NAs in the Wide format
na_stats <- patient_obs_wide %>%
select(- c(patient_num, days_since_admission, severity)) %>%
is.na() %>%
`!`
na_df <- data.frame(value_existed = colSums(na_stats),
prop_existed = colMeans(na_stats)) %>%
rownames_to_column('lab') %>%
mutate(prop_na = 1 - prop_existed,
lab = fct_reorder(lab, value_existed))
n_values <- na_df %>%
ggplot(aes(x = value_existed, y = lab)) +
geom_col() +
labs(x = 'Number of values', y = NULL)
na_prob <- na_df %>%
rename('Valid value' = prop_existed, 'NA' = prop_na) %>%
pivot_longer(c(`Valid value`, `NA`)) %>%
ggplot(aes(x = value, y = lab, fill = name)) +
geom_col() +
scale_fill_discrete(guide = guide_legend(reverse = TRUE)) +
labs(x = 'Proportion', y = NULL) +
# guides(fill = guide_legend(reverse = TRUE))
theme(
axis.text.y = element_blank(),
legend.key.width = unit(6, 'mm'),
legend.key.height = unit(4, 'mm'),
legend.position = 'bottom')
plot_grid(n_values, na_prob, nrow = 1, axis = 'b', align = 'h')

Analyze missingness and frequency of measures for each lab
patient_obs_long <- patient_obs_wide %>%
pivot_longer(-c(patient_num, days_since_admission, severity),
names_to = 'lab', values_to = 'value',
values_drop_na = TRUE)
per_lab <- patient_obs_long %>%
group_by(lab, patient_num, severity) %>%
count(name = 'n_obs') %>%
ungroup() %>%
group_by(lab, severity) %>%
count(n_obs) %>%
ungroup() %>%
pivot_wider(names_from = severity, values_from = n, values_fill = 0) %>%
mutate(both_severities = nonsevere + severe) %>%
mutate(prop_nonsevere = nonsevere/n_nonsevere,
prop_severe = severe/n_severe,
prop_both = both_severities/nrow(days_count_min_max))
lab_medians <-
patient_obs_long %>%
add_count(lab, name = 'total_obs') %>%
group_by(lab) %>%
mutate(total_patients = length(unique(patient_num))) %>%
add_count(patient_num, name = 'n_obs_patients') %>%
mutate(median_obs_per_patient = median(n_obs_patients),
n_greater0 = n_obs_patients > median_obs_per_patient,
n_greater1 = n_obs_patients > median_obs_per_patient + 1,
n_greater2 = n_obs_patients > median_obs_per_patient + 2) %>%
group_by(severity) %>%
mutate(each_med_obs_per_patient = median(n_obs_patients)) %>%
ungroup(severity) %>%
select(- c(days_since_admission, value)) %>%
distinct() %>%
group_by(lab) %>%
mutate(across(contains('n_greater'), sum)) %>%
select(- c(n_obs_patients, patient_num)) %>%
distinct() %>%
pivot_wider(names_from = severity, values_from = each_med_obs_per_patient) %>%
rename('median_obs_per_severe_patient' = severe,
'median_obs_per_non_severe_patient' = nonsevere) %>%
select(lab, total_obs, total_patients, starts_with('med'), starts_with('n_'))
lab_medians %>%
datatable(rownames = FALSE)
n_greater0 shows the number of patients who had more observations than the median. n_greater1 shows the number of patients who had more observations than the median + 1. n_greater2 shows the number of patients who had more observations than the median + 2.
In the figure below:
- Grey dash line:
Reference Low
- Grey solid line:
Reference High
- Black dash line:
lower bound outlier (QC)
- Black solid line:
upper bound outlier (QC)
patient_obs_long %>%
left_join(lab_bounds, by = c('lab' = 'short_name')) %>%
ggplot(aes(y = severity, x = value, fill = severity)) +
geom_violin() +
scale_fill_brewer(palette = 'Dark2', guide = guide_legend(reverse = TRUE)) +
labs(y = NULL, x = NULL) +
geom_vline(aes(xintercept = `Reference Low`), linetype = 'dashed', color = 'grey') +
geom_vline(aes(xintercept = `Reference High`), color = 'grey') +
geom_vline(aes(xintercept = LB), linetype = 'dashed') +
geom_vline(aes(xintercept = UB)) +
facet_wrap(~ lab, scales = 'free', ncol = 2, strip.position = 'left') +
theme(axis.text.y = element_blank())

Missing data heatmap
Capped at 20 days with observations.
per_lab %>%
select(lab, n_obs, both_severities, severe, nonsevere) %>%
filter(n_obs <= 20) %>%
pivot_longer(c(both_severities, severe, nonsevere)) %>%
mutate(name = name %>% fct_recode(
'All patients' = 'both_severities',
'Severe patients' = 'severe',
'Non-severe patients' = 'nonsevere'
)) %>%
ggplot(aes(x = n_obs, fill = value, y = fct_reorder(lab, n_obs))) +
geom_tile(colour = "white", size = 0.2)+
geom_text(aes(label = value), colour = "white", size = 2) +
scale_y_discrete(expand = c(0, 0))+
scale_x_continuous(expand = c(0, 0),
breaks = c(1:max(per_lab$n_obs)),
labels = c(1:max(per_lab$n_obs)))+
scale_fill_gradient(low = "lightgrey", high = "darkblue",
limits = c(0, max(per_lab$both_severities))) +
facet_wrap(~ name, nrow = 1) +
labs(x = 'Number of values a patient has for each lab',
y = NULL, fill = '# patients') +
theme(panel.grid.major = element_blank(),
legend.position = c(0.93, 0.2),
axis.ticks.y = element_blank()
)

“Binned” heatmap: every 15 days
per_lab %>%
mutate(obs_bin = cut(n_obs, breaks = 15, include.lowest = TRUE)) %>%
group_by(lab, obs_bin) %>%
summarise(both_severities = sum(both_severities),
severe = sum(severe),
nonsevere = sum(nonsevere),
.groups = 'drop') %>%
select(lab, obs_bin, both_severities, severe, nonsevere) %>%
pivot_longer(c(both_severities, severe, nonsevere)) %>%
mutate(name = name %>% fct_recode(
'All patients' = 'both_severities',
'Severe patients' = 'severe',
'Non-severe patients' = 'nonsevere'
)) %>%
ggplot(aes(x = obs_bin, fill = value, y = fct_reorder(lab, value))) +
geom_tile(colour = "white", size = 0.2) +
geom_text(aes(label = value), colour = "white", size = 2) +
scale_y_discrete(expand = c(0, 0))+
scale_fill_gradient(low = "lightgrey", high = "darkblue") +
facet_wrap(~ name, nrow = 1) +
labs(x = 'Number of values a patient has for each lab',
y = NULL, fill = '# patients') +
theme(panel.grid.major = element_blank(),
legend.position = c(0.93, 0.2),
axis.text.x = element_text(angle = 90, hjust = 1),
axis.ticks.y = element_blank()
)


## [1] 15
per_lab %>%
select(lab, n_obs, prop_both, prop_severe, prop_nonsevere) %>%
filter(n_obs <= 20) %>%
pivot_longer(c(prop_both, prop_severe, prop_nonsevere)) %>%
mutate(name = name %>% fct_recode(
'Compared to all patients' = 'prop_both',
'Compared to all severe patients' = 'prop_severe',
'Compared to all non-severe patients' = 'prop_nonsevere'
)) %>%
ggplot(aes(x = n_obs, fill = value, y = fct_reorder(lab, n_obs))) +
geom_tile(colour = "white", size = 0.2)+
geom_text(aes(label = round(value, 2)), colour = "white", size = 2) +
scale_y_discrete(expand = c(0, 0)) +
scale_x_continuous(expand = c(0, 0),
breaks = c(1:max(per_lab$n_obs)),
labels = c(1:max(per_lab$n_obs)))+
scale_fill_gradient(low = "lightgrey", high = "darkblue",
labels = scales::percent_format(accuracy = 1L)) +
facet_wrap(~ name, nrow = 1) +
labs(x = 'Number of values a patient has for each lab',
y = NULL, fill = '% patients') +
theme(panel.grid.major = element_blank(),
legend.position = c(0.93, 0.2),
axis.ticks.y = element_blank()
)

per_lab %>%
mutate(obs_bin = cut(n_obs, breaks = 15, include.lowest = TRUE)) %>%
group_by(lab, obs_bin) %>%
summarise(prop_both = sum(prop_both),
prop_severe = sum(prop_severe),
prop_nonsevere = sum(prop_nonsevere),
.groups = 'drop') %>%
select(lab, obs_bin, prop_both, prop_severe, prop_nonsevere) %>%
pivot_longer(c(prop_both, prop_severe, prop_nonsevere)) %>%
mutate(name = name %>% fct_recode(
'Compared to all patients' = 'prop_both',
'Compared to all severe patients' = 'prop_severe',
'Compared to all non-severe patients' = 'prop_nonsevere'
)) %>%
ggplot(aes(x = obs_bin, fill = value, y = fct_reorder(lab, value))) +
geom_tile(colour = "white", size = 0.2) +
geom_text(aes(label = round(value, 2)), colour = "white", size = 2) +
scale_y_discrete(expand = c(0, 0)) +
scale_fill_gradient(low = "lightgrey", high = "darkblue",
labels = scales::percent_format(accuracy = 1L)) +
facet_wrap(~ name, nrow = 1) +
labs(x = 'Number of values a patient has for each lab',
y = NULL, fill = '% patients') +
theme(panel.grid.major = element_blank(),
legend.position = c(0.93, 0.2),
axis.text.x = element_text(angle = 90, hjust = 1),
axis.ticks.y = element_blank()
)

Denominator: total number of patients, total number of non-severe patients, and total number of severe patients, respectively.
per_lab %>%
select(lab, n_obs, severe, nonsevere) %>%
filter(n_obs <= 90) %>%
pivot_longer(c(severe, nonsevere)) %>%
mutate(lab = fct_reorder(lab, n_obs),
name = name %>% fct_recode(
'Severe patients' = 'severe',
'Non-severe patients' = 'nonsevere'
)) %>%
ggplot(aes(x = n_obs, fill = name, y = value)) +
geom_col() +
scale_fill_brewer(palette = 'Dark2', direction = -1) +
facet_wrap(~ lab, scales = 'free') +
labs(x = 'Number of values a patient has for each lab',
y = NULL, fill = '# patients') +
theme(panel.grid.major = element_blank(),
legend.position = c(0.9, 0.2),
axis.ticks.y = element_blank()
)

## R version 4.0.3 (2020-10-10)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.7
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] cowplot_1.1.0 tibble_3.0.4 DT_0.16 forcats_0.5.0 tidyr_1.1.2
## [6] dplyr_1.0.2 readr_1.4.0 ggplot2_3.3.2
##
## loaded via a namespace (and not attached):
## [1] RColorBrewer_1.1-2 pillar_1.4.6 compiler_4.0.3 tools_4.0.3
## [5] digest_0.6.27 jsonlite_1.7.1 evaluate_0.14 lifecycle_0.2.0
## [9] gtable_0.3.0 pkgconfig_2.0.3 rlang_0.4.8 rstudioapi_0.13
## [13] cli_2.1.0 crosstalk_1.1.0.1 yaml_2.2.1 xfun_0.19
## [17] withr_2.3.0 stringr_1.4.0 knitr_1.30 generics_0.1.0
## [21] vctrs_0.3.4 htmlwidgets_1.5.2 hms_0.5.3 grid_4.0.3
## [25] tidyselect_1.1.0 glue_1.4.2 R6_2.5.0 fansi_0.4.1
## [29] rmarkdown_2.5 farver_2.0.3 purrr_0.3.4 magrittr_1.5
## [33] scales_1.1.1 ellipsis_0.3.1 htmltools_0.5.0 assertthat_0.2.1
## [37] colorspace_2.0-0 labeling_0.4.2 stringi_1.5.3 munsell_0.5.0
## [41] crayon_1.3.4
LS0tCnRpdGxlOiAiTWlzc2luZ25lc3MgYW5hbHlzaXMiCmF1dGhvcjogQW1lbGlhIFRhbiwgQXJpYW5uYSBEYWdsaWF0aSwgVHJhbmcgTGUKZGF0ZTogIjI3IE9jdG9iZXIgMjAyMCIKLS0tCgoKYGBge3Igc2V0dXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShjb3dwbG90KQoKdGhlbWVfc2V0KHRoZW1lX2J3KCkgKyAKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSkKYGBgCgojIyBSZWFkIGluIGZpbGVzIAphbmQgY29udmVydCB0byB3aWRlIGZvcm1hdApgYGB7UiBtZXNzYWdlPUZBTFNFfQojNENFIGxvbmcgZm9ybWF0IExhYnMgRGF0YQpwYXRpZW50X29icyA8LSByZWFkX2NzdigncGVubi1kYXRhL2xhYnNfbG9uZ190aHJvbWJvX3YyLmNzdicpICU+JSAKICBtdXRhdGUoc2V2ZXJpdHkgPSAoc2V2ZXJlX2luZCA9PSAxKSAlPiUgCiAgICAgICAgICAgYXNfZmFjdG9yKCkgJT4lIAogICAgICAgICAgIGZjdF9yZWNvZGUoJ25vbnNldmVyZScgPSAnRkFMU0UnLCAnc2V2ZXJlJyA9ICdUUlVFJykpCgojQ29kZSwgRGVzY3JpcHRpb25zIGFuZCBSYW5nZXMKbGFiX21hcHBpbmcgPC0gcmVhZF9jc3YoJ3B1YmxpYy1kYXRhL2xvaW5jLW1hcC5jc3YnKQpsb2FkKCdwdWJsaWMtZGF0YS9sYWIucmFuZ2UucmRhJykKIyBsb2FkKCdwdWJsaWMtZGF0YS9jb2RlLmRpY3QucmRhJykKYGBgCgpgYGB7cn0KbGFiX2JvdW5kcyA8LSBsYWIucmFuZ2VbLCAtMV0gJT4lIAogIGNvbE1lYW5zKCkgJT4lIAogIGRhdGEuZnJhbWUodmFsdWUgPSAuKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIHNlcGFyYXRlKGNvbCA9IHJvd25hbWUsIGludG8gPSBjKCdMT0lOQycsICdib3VuZCcpLCBzZXAgPSAnXycpICU+JSAKICBtdXRhdGUoTE9JTkMgPSBnc3ViKCdsb2luYycsICcnLCBMT0lOQykgJT4lIGdzdWIoJ1xcLicsICctJywgLiksCiAgICAgICAgIHZhbHVlID0gZXhwKHZhbHVlKSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAnYm91bmQnLCB2YWx1ZXNfZnJvbSA9ICd2YWx1ZScpICU+JQogIGxlZnRfam9pbihsYWJfbWFwcGluZywgYnkgPSAnTE9JTkMnKSAlPiUKICB7Ln0KYGBgCgpgYGB7Un0KcGF0aWVudF9vYnNfd2lkZSA8LSBwYXRpZW50X29icyAlPiUgCiAgbGVmdF9qb2luKGxhYl9ib3VuZHMsIGJ5ID0gYygnY29uY2VwdF9jb2RlJyA9ICdMT0lOQycpKSAlPiUgCiAgc2VsZWN0KC0gY29uY2VwdF9jb2RlKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMocGF0aWVudF9udW0sIGRheXNfc2luY2VfYWRtaXNzaW9uLCBzZXZlcml0eSksCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IHNob3J0X25hbWUsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSB2YWx1ZSwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBtZWFuKQoKI2NoZWNrIE5BcyBpbiB0aGUgV2lkZSBmb3JtYXQKbmFfc3RhdHMgPC0gcGF0aWVudF9vYnNfd2lkZSAlPiUgCiAgc2VsZWN0KC0gYyhwYXRpZW50X251bSwgZGF5c19zaW5jZV9hZG1pc3Npb24sIHNldmVyaXR5KSkgJT4lIAogIGlzLm5hKCkgJT4lIAogIGAhYCAKCm5hX2RmIDwtIGRhdGEuZnJhbWUodmFsdWVfZXhpc3RlZCA9IGNvbFN1bXMobmFfc3RhdHMpLCAKICAgICAgICAgICBwcm9wX2V4aXN0ZWQgPSBjb2xNZWFucyhuYV9zdGF0cykpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oJ2xhYicpICU+JSAKICBtdXRhdGUocHJvcF9uYSA9IDEgLSBwcm9wX2V4aXN0ZWQsCiAgICAgICAgIGxhYiA9IGZjdF9yZW9yZGVyKGxhYiwgdmFsdWVfZXhpc3RlZCkpCgpuX3ZhbHVlcyA8LSBuYV9kZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdmFsdWVfZXhpc3RlZCwgeSA9IGxhYikpICsKICBnZW9tX2NvbCgpICsgCiAgbGFicyh4ID0gJ051bWJlciBvZiB2YWx1ZXMnLCB5ID0gTlVMTCkKCm5hX3Byb2IgPC0gbmFfZGYgJT4lCiAgcmVuYW1lKCdWYWxpZCB2YWx1ZScgPSBwcm9wX2V4aXN0ZWQsICdOQScgPSBwcm9wX25hKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGMoYFZhbGlkIHZhbHVlYCwgYE5BYCkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSwgeSA9IGxhYiwgZmlsbCA9IG5hbWUpKSArCiAgZ2VvbV9jb2woKSArIAogIHNjYWxlX2ZpbGxfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArCiAgbGFicyh4ID0gJ1Byb3BvcnRpb24nLCB5ID0gTlVMTCkgKwogICMgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKQogIHRoZW1lKAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCg2LCAnbW0nKSwKICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCg0LCAnbW0nKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKQoKcGxvdF9ncmlkKG5fdmFsdWVzLCBuYV9wcm9iLCBucm93ID0gMSwgYXhpcyA9ICdiJywgYWxpZ24gPSAnaCcpCgpwZW5uX25hX2RmIDwtIG5hX2RmCmBgYAoKIyMgTnVtYmVyIG9mIG9ic2VydmF0aW9uIChkYXlzKSBwZXIgcGF0aWVudApgYGB7Un0KZGF5c19jb3VudF9taW5fbWF4IDwtIHBhdGllbnRfb2JzX3dpZGUgJT4lCiAgZ3JvdXBfYnkocGF0aWVudF9udW0sIHNldmVyaXR5KSAlPiUKICBzdW1tYXJpc2UoCiAgICBuX3ZhbHVlcyA9IG5fZGlzdGluY3QoZGF5c19zaW5jZV9hZG1pc3Npb24pLAogICAgbWluX2RheSA9IG1pbihkYXlzX3NpbmNlX2FkbWlzc2lvbiksCiAgICBtYXhfZGF5ID0gbWF4KGRheXNfc2luY2VfYWRtaXNzaW9uKSwKICAgIC5ncm91cHMgPSAnZHJvcCcKICApICU+JSAKICBtdXRhdGUodGltZV9vYnMgPSBtYXhfZGF5IC0gbWluX2RheSkgJT4lIAogIHNlbGVjdCgtcGF0aWVudF9udW0pICU+JSAKICBhZGRfY291bnQoc2V2ZXJpdHksIG5hbWUgPSAnbl9zZXZlcml0eScpIAoKYWdnX25fdmFsdWVzIDwtIGRheXNfY291bnRfbWluX21heCAlPiUgCiAgY291bnQoc2V2ZXJpdHksIG5fc2V2ZXJpdHksIG5fdmFsdWVzLAogICAgICAgIG5hbWUgPSAnbl9udmFscycpCmFnZ19tYXhfZGF5IDwtIGRheXNfY291bnRfbWluX21heCAlPiUgCiAgY291bnQoc2V2ZXJpdHksIG5fc2V2ZXJpdHksIG1heF9kYXksCiAgICAgICAgbmFtZSA9ICduX21heGRheScpCgoobl9zZXZlcmUgPC0gc3VtKGRheXNfY291bnRfbWluX21heCRzZXZlcml0eSA9PSAnc2V2ZXJlJykpCihuX25vbnNldmVyZSA8LSBzdW0oZGF5c19jb3VudF9taW5fbWF4JHNldmVyaXR5ID09ICdub25zZXZlcmUnKSkKIyBzdW1tYXJ5KGRheXNfY291bnRfbWluX21heCRuX3ZhbHVlcykKYGBgCgojIyBIaXN0b2dyYW0gb2YgdGhlIG51bWJlciBvZiBkYXlzIHdpdGggYXQgbGVhc3Qgb25lIG9ic2VydmF0aW9uCmBgYHtSfQphZ2dfbl92YWx1ZXMgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fdmFsdWVzLCB5ID0gbl9udmFscywgZmlsbCA9IHNldmVyaXR5KSkgKwogIGdlb21fY29sKGFscGhhID0gMC41KSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICdEYXJrMicsIGRpcmVjdGlvbiA9IC0xKSArCiAgbGFicyhmaWxsID0gJ1NldmVyZT8nLCAKICAgICAgIHggPSAiTnVtYmVyIG9mIGRheXMgd2l0aCBkYXRhIiwgCiAgICAgICB5ID0gIkNvdW50IikKYGBgCgojIyBIaXN0b2dyYW0gb2YgbGVuZ3RoIG9mIHN0YXkKaS5lLiBsYXN0IGRheSB3aXRoIG9ic2VydmF0aW9uLWZpcnN0IGRheSB3aXRoIG9ic2VydmF0aW9uCgpXZSBuZWVkIHRvIGNoZWNrIGZvciByZWFkbWlzc2lvbiBoZXJlLgpgYGB7Un0KYWdnX21heF9kYXkgJT4lIAogIGdncGxvdChhZXMoeCA9IG1heF9kYXksIHkgPSBuX21heGRheSwgZmlsbCA9IHNldmVyaXR5KSkgKwogIGdlb21fY29sKGFscGhhID0gMC41KSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICdEYXJrMicsIGRpcmVjdGlvbiA9IC0xKSArCiAgbGFicyhmaWxsID0gJ1NldmVyZT8nLCAKICAgICAgIHggPSAiTnVtYmVyIG9mIGRheXMgd2l0aCBkYXRhIiwgCiAgICAgICB5ID0gIkNvdW50IikKYGBgCgojIyBBbmFseXplIG1pc3NpbmduZXNzIGFuZCBmcmVxdWVuY3kgb2YgbWVhc3VyZXMgZm9yIGVhY2ggbGFiCgpgYGB7cn0KcGF0aWVudF9vYnNfbG9uZyA8LSBwYXRpZW50X29ic193aWRlICU+JSAKICBwaXZvdF9sb25nZXIoLWMocGF0aWVudF9udW0sIGRheXNfc2luY2VfYWRtaXNzaW9uLCBzZXZlcml0eSksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gJ2xhYicsIHZhbHVlc190byA9ICd2YWx1ZScsCiAgICAgICAgICAgICAgIHZhbHVlc19kcm9wX25hID0gVFJVRSkKICAKcGVyX2xhYiA8LSBwYXRpZW50X29ic19sb25nICU+JSAKICBncm91cF9ieShsYWIsIHBhdGllbnRfbnVtLCBzZXZlcml0eSkgJT4lIAogIGNvdW50KG5hbWUgPSAnbl9vYnMnKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShsYWIsIHNldmVyaXR5KSAlPiUgCiAgY291bnQobl9vYnMpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXZlcml0eSwgdmFsdWVzX2Zyb20gPSBuLCB2YWx1ZXNfZmlsbCA9IDApICU+JSAKICBtdXRhdGUoYm90aF9zZXZlcml0aWVzID0gbm9uc2V2ZXJlICsgc2V2ZXJlKSAlPiUgCiAgbXV0YXRlKHByb3Bfbm9uc2V2ZXJlID0gbm9uc2V2ZXJlL25fbm9uc2V2ZXJlLAogICAgICAgICBwcm9wX3NldmVyZSA9IHNldmVyZS9uX3NldmVyZSwKICAgICAgICAgcHJvcF9ib3RoID0gYm90aF9zZXZlcml0aWVzL25yb3coZGF5c19jb3VudF9taW5fbWF4KSkKCmxhYl9tZWRpYW5zIDwtCiAgcGF0aWVudF9vYnNfbG9uZyAlPiUgCiAgYWRkX2NvdW50KGxhYiwgbmFtZSA9ICd0b3RhbF9vYnMnKSAlPiUgCiAgZ3JvdXBfYnkobGFiKSAlPiUgCiAgbXV0YXRlKHRvdGFsX3BhdGllbnRzID0gbGVuZ3RoKHVuaXF1ZShwYXRpZW50X251bSkpKSAlPiUgCiAgYWRkX2NvdW50KHBhdGllbnRfbnVtLCBuYW1lID0gJ25fb2JzX3BhdGllbnRzJykgJT4lIAogIG11dGF0ZShtZWRpYW5fb2JzX3Blcl9wYXRpZW50ID0gbWVkaWFuKG5fb2JzX3BhdGllbnRzKSwKICAgICAgICAgbl9ncmVhdGVyMCA9IG5fb2JzX3BhdGllbnRzID4gbWVkaWFuX29ic19wZXJfcGF0aWVudCwKICAgICAgICAgbl9ncmVhdGVyMSA9IG5fb2JzX3BhdGllbnRzID4gbWVkaWFuX29ic19wZXJfcGF0aWVudCArIDEsCiAgICAgICAgIG5fZ3JlYXRlcjIgPSBuX29ic19wYXRpZW50cyA+IG1lZGlhbl9vYnNfcGVyX3BhdGllbnQgKyAyKSAlPiUgCiAgZ3JvdXBfYnkoc2V2ZXJpdHkpICU+JSAKICBtdXRhdGUoZWFjaF9tZWRfb2JzX3Blcl9wYXRpZW50ID0gbWVkaWFuKG5fb2JzX3BhdGllbnRzKSkgJT4lIAogIHVuZ3JvdXAoc2V2ZXJpdHkpICU+JSAKICBzZWxlY3QoLSBjKGRheXNfc2luY2VfYWRtaXNzaW9uLCB2YWx1ZSkpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShsYWIpICU+JSAKICBtdXRhdGUoYWNyb3NzKGNvbnRhaW5zKCduX2dyZWF0ZXInKSwgc3VtKSkgJT4lIAogIHNlbGVjdCgtIGMobl9vYnNfcGF0aWVudHMsIHBhdGllbnRfbnVtKSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXZlcml0eSwgdmFsdWVzX2Zyb20gPSBlYWNoX21lZF9vYnNfcGVyX3BhdGllbnQpICU+JSAKICByZW5hbWUoJ21lZGlhbl9vYnNfcGVyX3NldmVyZV9wYXRpZW50JyA9IHNldmVyZSwKICAgICAgICAgJ21lZGlhbl9vYnNfcGVyX25vbl9zZXZlcmVfcGF0aWVudCcgPSBub25zZXZlcmUpICU+JSAKICBzZWxlY3QobGFiLCB0b3RhbF9vYnMsIHRvdGFsX3BhdGllbnRzLCBzdGFydHNfd2l0aCgnbWVkJyksIHN0YXJ0c193aXRoKCduXycpKQoKbGFiX21lZGlhbnMgJT4lIAogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCgpgbl9ncmVhdGVyMGAgc2hvd3MgdGhlIG51bWJlciBvZiBwYXRpZW50cyB3aG8gaGFkIG1vcmUgb2JzZXJ2YXRpb25zIHRoYW4gdGhlIG1lZGlhbi4KYG5fZ3JlYXRlcjFgIHNob3dzIHRoZSBudW1iZXIgb2YgcGF0aWVudHMgd2hvIGhhZCBtb3JlIG9ic2VydmF0aW9ucyB0aGFuIHRoZSBtZWRpYW4gKyAxLgpgbl9ncmVhdGVyMmAgc2hvd3MgdGhlIG51bWJlciBvZiBwYXRpZW50cyB3aG8gaGFkIG1vcmUgb2JzZXJ2YXRpb25zIHRoYW4gdGhlIG1lZGlhbiArIDIuCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsYWJfbWVkaWFucyAlPiUgCiAgc2VsZWN0KGxhYiwgdG90YWxfb2JzLCB0b3RhbF9wYXRpZW50cykgJT4lCiAgcGl2b3RfbG9uZ2VyKC0gbGFiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdmFsdWUsIHkgPSBmY3RfcmVvcmRlcihsYWIsIHZhbHVlKSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKG5hbWUpLCBzY2FsZXMgPSAnZnJlZV94Jywgc3BhY2UgPSAnZnJlZScpICsKICBsYWJzKHkgPSBOVUxMKQpgYGAKCkluIHRoZSBmaWd1cmUgYmVsb3c6CgotIEdyZXkgZGFzaCBsaW5lOiBgUmVmZXJlbmNlIExvd2AKLSBHcmV5IHNvbGlkIGxpbmU6IGBSZWZlcmVuY2UgSGlnaGAKLSBCbGFjayBkYXNoIGxpbmU6IGBsb3dlciBib3VuZCBvdXRsaWVyYCAoUUMpCi0gQmxhY2sgc29saWQgbGluZTogYHVwcGVyIGJvdW5kIG91dGxpZXJgIChRQykKCmBgYHtyIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTExfQpwYXRpZW50X29ic19sb25nICU+JSAKICBsZWZ0X2pvaW4obGFiX2JvdW5kcywgYnkgPSBjKCdsYWInID0gJ3Nob3J0X25hbWUnKSkgJT4lIAogIGdncGxvdChhZXMoeSA9IHNldmVyaXR5LCB4ID0gdmFsdWUsIGZpbGwgPSBzZXZlcml0eSkpICsKICBnZW9tX3Zpb2xpbigpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gJ0RhcmsyJywgZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArCiAgbGFicyh5ID0gTlVMTCwgeCA9IE5VTEwpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gYFJlZmVyZW5jZSBMb3dgKSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAnZ3JleScpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gYFJlZmVyZW5jZSBIaWdoYCksIGNvbG9yID0gJ2dyZXknKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IExCKSwgbGluZXR5cGUgPSAnZGFzaGVkJykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBVQikpICsKICBmYWNldF93cmFwKH4gbGFiLCBzY2FsZXMgPSAnZnJlZScsIG5jb2wgPSAyLCBzdHJpcC5wb3NpdGlvbiA9ICdsZWZ0JykgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIE1pc3NpbmcgZGF0YSBoZWF0bWFwCgpDYXBwZWQgYXQgMjAgZGF5cyB3aXRoIG9ic2VydmF0aW9ucy4KCmBgYHtyIGZpZy53aWR0aD0xMn0KcGVyX2xhYiAlPiUgCiAgc2VsZWN0KGxhYiwgbl9vYnMsIGJvdGhfc2V2ZXJpdGllcywgc2V2ZXJlLCBub25zZXZlcmUpICU+JSAKICBmaWx0ZXIobl9vYnMgPD0gMjApICU+JSAKICBwaXZvdF9sb25nZXIoYyhib3RoX3NldmVyaXRpZXMsIHNldmVyZSwgbm9uc2V2ZXJlKSkgJT4lIAogIG11dGF0ZShuYW1lID0gbmFtZSAlPiUgZmN0X3JlY29kZSgKICAgICdBbGwgcGF0aWVudHMnID0gJ2JvdGhfc2V2ZXJpdGllcycsCiAgICAnU2V2ZXJlIHBhdGllbnRzJyA9ICdzZXZlcmUnLAogICAgJ05vbi1zZXZlcmUgcGF0aWVudHMnID0gJ25vbnNldmVyZScKICApKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbl9vYnMsIGZpbGwgPSB2YWx1ZSwgeSA9IGZjdF9yZW9yZGVyKGxhYiwgbl9vYnMpKSkgKyAKICBnZW9tX3RpbGUoY29sb3VyID0gIndoaXRlIiwgc2l6ZSA9IDAuMikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZhbHVlKSwgY29sb3VyID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDE6bWF4KHBlcl9sYWIkbl9vYnMpKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOm1heChwZXJfbGFiJG5fb2JzKSkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImxpZ2h0Z3JleSIsIGhpZ2ggPSAiZGFya2JsdWUiLAogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCBtYXgocGVyX2xhYiRib3RoX3NldmVyaXRpZXMpKSkgKwogIGZhY2V0X3dyYXAofiBuYW1lLCBucm93ID0gMSkgKwogIGxhYnMoeCA9ICdOdW1iZXIgb2YgdmFsdWVzIGEgcGF0aWVudCBoYXMgZm9yIGVhY2ggbGFiJywKICAgICAgIHkgPSBOVUxMLCBmaWxsID0gJyMgcGF0aWVudHMnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOTMsIDAuMiksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpCiAgKQpgYGAKCiJCaW5uZWQiIGhlYXRtYXA6IGV2ZXJ5IDE1IGRheXMKCmBgYHtyIGZpZy53aWR0aD0xMn0KcGVyX2xhYiAlPiUKICBtdXRhdGUob2JzX2JpbiA9IGN1dChuX29icywgYnJlYWtzID0gMTUsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpICU+JSAKICBncm91cF9ieShsYWIsIG9ic19iaW4pICU+JSAKICBzdW1tYXJpc2UoYm90aF9zZXZlcml0aWVzID0gc3VtKGJvdGhfc2V2ZXJpdGllcyksIAogICAgICAgICAgICBzZXZlcmUgPSBzdW0oc2V2ZXJlKSwgCiAgICAgICAgICAgIG5vbnNldmVyZSA9IHN1bShub25zZXZlcmUpLCAKICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykgJT4lIAogIHNlbGVjdChsYWIsIG9ic19iaW4sIGJvdGhfc2V2ZXJpdGllcywgc2V2ZXJlLCBub25zZXZlcmUpICU+JSAKICBwaXZvdF9sb25nZXIoYyhib3RoX3NldmVyaXRpZXMsIHNldmVyZSwgbm9uc2V2ZXJlKSkgJT4lIAogIG11dGF0ZShuYW1lID0gbmFtZSAlPiUgZmN0X3JlY29kZSgKICAgICdBbGwgcGF0aWVudHMnID0gJ2JvdGhfc2V2ZXJpdGllcycsCiAgICAnU2V2ZXJlIHBhdGllbnRzJyA9ICdzZXZlcmUnLAogICAgJ05vbi1zZXZlcmUgcGF0aWVudHMnID0gJ25vbnNldmVyZScKICApKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gb2JzX2JpbiwgZmlsbCA9IHZhbHVlLCB5ID0gZmN0X3Jlb3JkZXIobGFiLCB2YWx1ZSkpKSArIAogIGdlb21fdGlsZShjb2xvdXIgPSAid2hpdGUiLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZhbHVlKSwgY29sb3VyID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImxpZ2h0Z3JleSIsIGhpZ2ggPSAiZGFya2JsdWUiKSArCiAgZmFjZXRfd3JhcCh+IG5hbWUsIG5yb3cgPSAxKSArCiAgbGFicyh4ID0gJ051bWJlciBvZiB2YWx1ZXMgYSBwYXRpZW50IGhhcyBmb3IgZWFjaCBsYWInLAogICAgICAgeSA9IE5VTEwsIGZpbGwgPSAnIyBwYXRpZW50cycpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45MywgMC4yKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKYGBgCgpgYGB7cn0KYm94cGxvdChwZXJfbGFiJG5fb2JzKQpzdW0ocGVyX2xhYiRuX29icyA+IDkwKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMn0KcGVyX2xhYiAlPiUgCiAgc2VsZWN0KGxhYiwgbl9vYnMsIHByb3BfYm90aCwgcHJvcF9zZXZlcmUsIHByb3Bfbm9uc2V2ZXJlKSAlPiUgCiAgZmlsdGVyKG5fb2JzIDw9IDIwKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGMocHJvcF9ib3RoLCBwcm9wX3NldmVyZSwgcHJvcF9ub25zZXZlcmUpKSAlPiUgCiAgbXV0YXRlKG5hbWUgPSBuYW1lICU+JSBmY3RfcmVjb2RlKAogICAgJ0NvbXBhcmVkIHRvIGFsbCBwYXRpZW50cycgPSAncHJvcF9ib3RoJywKICAgICdDb21wYXJlZCB0byBhbGwgc2V2ZXJlIHBhdGllbnRzJyA9ICdwcm9wX3NldmVyZScsCiAgICAnQ29tcGFyZWQgdG8gYWxsIG5vbi1zZXZlcmUgcGF0aWVudHMnID0gJ3Byb3Bfbm9uc2V2ZXJlJwogICkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBuX29icywgZmlsbCA9IHZhbHVlLCB5ID0gZmN0X3Jlb3JkZXIobGFiLCBuX29icykpKSArIAogIGdlb21fdGlsZShjb2xvdXIgPSAid2hpdGUiLCBzaXplID0gMC4yKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQodmFsdWUsIDIpKSwgY29sb3VyID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygxOm1heChwZXJfbGFiJG5fb2JzKSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTptYXgocGVyX2xhYiRuX29icykpKSsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAibGlnaHRncmV5IiwgaGlnaCA9ICJkYXJrYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMUwpKSArCiAgZmFjZXRfd3JhcCh+IG5hbWUsIG5yb3cgPSAxKSArCiAgbGFicyh4ID0gJ051bWJlciBvZiB2YWx1ZXMgYSBwYXRpZW50IGhhcyBmb3IgZWFjaCBsYWInLAogICAgICAgeSA9IE5VTEwsIGZpbGwgPSAnJSBwYXRpZW50cycpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45MywgMC4yKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoKYGBge3IgZmlnLndpZHRoPTEyfQpwZXJfbGFiICU+JQogIG11dGF0ZShvYnNfYmluID0gY3V0KG5fb2JzLCBicmVha3MgPSAxNSwgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkgJT4lIAogIGdyb3VwX2J5KGxhYiwgb2JzX2JpbikgJT4lIAogIHN1bW1hcmlzZShwcm9wX2JvdGggPSBzdW0ocHJvcF9ib3RoKSwgCiAgICAgICAgICAgIHByb3Bfc2V2ZXJlID0gc3VtKHByb3Bfc2V2ZXJlKSwgCiAgICAgICAgICAgIHByb3Bfbm9uc2V2ZXJlID0gc3VtKHByb3Bfbm9uc2V2ZXJlKSwgCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICBzZWxlY3QobGFiLCBvYnNfYmluLCBwcm9wX2JvdGgsIHByb3Bfc2V2ZXJlLCBwcm9wX25vbnNldmVyZSkgJT4lIAogIHBpdm90X2xvbmdlcihjKHByb3BfYm90aCwgcHJvcF9zZXZlcmUsIHByb3Bfbm9uc2V2ZXJlKSkgJT4lIAogIG11dGF0ZShuYW1lID0gbmFtZSAlPiUgZmN0X3JlY29kZSgKICAgICdDb21wYXJlZCB0byBhbGwgcGF0aWVudHMnID0gJ3Byb3BfYm90aCcsCiAgICAnQ29tcGFyZWQgdG8gYWxsIHNldmVyZSBwYXRpZW50cycgPSAncHJvcF9zZXZlcmUnLAogICAgJ0NvbXBhcmVkIHRvIGFsbCBub24tc2V2ZXJlIHBhdGllbnRzJyA9ICdwcm9wX25vbnNldmVyZScKICApKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gb2JzX2JpbiwgZmlsbCA9IHZhbHVlLCB5ID0gZmN0X3Jlb3JkZXIobGFiLCB2YWx1ZSkpKSArIAogIGdlb21fdGlsZShjb2xvdXIgPSAid2hpdGUiLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIGNvbG91ciA9ICJ3aGl0ZSIsIHNpemUgPSAyKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAibGlnaHRncmV5IiwgaGlnaCA9ICJkYXJrYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMUwpKSArCiAgZmFjZXRfd3JhcCh+IG5hbWUsIG5yb3cgPSAxKSArCiAgbGFicyh4ID0gJ051bWJlciBvZiB2YWx1ZXMgYSBwYXRpZW50IGhhcyBmb3IgZWFjaCBsYWInLAogICAgICAgeSA9IE5VTEwsIGZpbGwgPSAnJSBwYXRpZW50cycpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45MywgMC4yKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKYGBgCgpEZW5vbWluYXRvcjogdG90YWwgbnVtYmVyIG9mIHBhdGllbnRzLCB0b3RhbCBudW1iZXIgb2Ygbm9uLXNldmVyZSBwYXRpZW50cywKYW5kIHRvdGFsIG51bWJlciBvZiBzZXZlcmUgcGF0aWVudHMsIHJlc3BlY3RpdmVseS4KCmBgYHtyfQpwZXJfbGFiICU+JSAKICBzZWxlY3QobGFiLCBuX29icywgc2V2ZXJlLCBub25zZXZlcmUpICU+JSAKICBmaWx0ZXIobl9vYnMgPD0gOTApICU+JQogIHBpdm90X2xvbmdlcihjKHNldmVyZSwgbm9uc2V2ZXJlKSkgJT4lIAogIG11dGF0ZShsYWIgPSBmY3RfcmVvcmRlcihsYWIsIG5fb2JzKSwKICAgICAgICAgbmFtZSA9IG5hbWUgJT4lIGZjdF9yZWNvZGUoCiAgICAnU2V2ZXJlIHBhdGllbnRzJyA9ICdzZXZlcmUnLAogICAgJ05vbi1zZXZlcmUgcGF0aWVudHMnID0gJ25vbnNldmVyZScKICApKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbl9vYnMsIGZpbGwgPSBuYW1lLCB5ID0gdmFsdWUpKSArIAogIGdlb21fY29sKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAnRGFyazInLCBkaXJlY3Rpb24gPSAtMSkgKwogIGZhY2V0X3dyYXAofiBsYWIsIHNjYWxlcyA9ICdmcmVlJykgKwogIGxhYnMoeCA9ICdOdW1iZXIgb2YgdmFsdWVzIGEgcGF0aWVudCBoYXMgZm9yIGVhY2ggbGFiJywKICAgICAgIHkgPSBOVUxMLCBmaWxsID0gJyMgcGF0aWVudHMnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwgMC4yKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=